package com.aps.server.parse.utils;

import com.aps.server.parse.ann.ExcelColumn;
import com.aps.server.parse.ann.ExcelParser;
import com.aps.server.parse.model.ExcelColumnConfig;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.DateUtil;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.springframework.util.Assert;
import org.springframework.util.ObjectUtils;

import java.lang.reflect.Field;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @Author nbZhuozh
 * @Date 2025-08-29  10:47
 *
 * excel解析类，确认实体、表头、数据等
 * return key:index value:对应entity配置的 @ExcelColumn的值
 **/
public class ExcelParserUtil {

    public final static String ROW_INDEX = "_ROW_INDEX::";

    public final static DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");

    //返回 excel header_index 对应 实体的 字段名称
    public static Map<String, String> parseHeaderMapping(Sheet sheet, Class<?> entityClass) {
        Assert.notNull(sheet, "sheet must not be null");
        Assert.notNull(entityClass, "entityClass must not be null");

        Map<String, String> mapping = new HashMap<>();
        Row headerRow = sheet.getRow(0);
        if (headerRow == null) {
            throw new RuntimeException("Excel文件格式错误：缺少表头行");
        }
        // 获取实体字段映射
        Map<String, String> fieldMapping = getFieldMapping(entityClass);

        for (Cell cell : headerRow) {
            String headerValue = cell.getStringCellValue().trim();
            String fieldName = fieldMapping.get(headerValue);
            if (fieldName != null) {
                mapping.put(String.valueOf(cell.getColumnIndex()), fieldName);
            }
        }

        return mapping;
    }

    /**
     * NOTES 根据实体类 找到对应字段的excelColumn注解，获取属性名称 ，默认使用字段名
     * key : 配置的名称 ， value：字段英文
     * @param entityClass
     * @return
     */
    public static Map<String, String> getFieldMapping(Class<?> entityClass) {
        Map<String, String> mapping = new HashMap<>();
        Field[] fields = entityClass.getDeclaredFields();
        Arrays.stream(fields).forEach(field -> {
            ExcelColumn annotation = field.getAnnotation(ExcelColumn.class);
            if(annotation != null) {
                String fieldName = annotation != null ? annotation.value() : field.getName();
                mapping.put(fieldName, field.getName());
            }
        });
        return mapping;
    }

    /**
     * 读取 sheet 数据
     * 返回 key:属性名称（entitiyClass中 字段注解的值） value:单元格值；
     * @param sheet
     * @param headerMapping
     * @return
     */
    public static List<Map<String, Object>> parseExcelMapping(Sheet sheet, Map<String, String> headerMapping) {
        List<Map<String, Object>> dataList = new ArrayList<>();
        for (int i = 1; i <= sheet.getLastRowNum(); i++) {
            Row row = sheet.getRow(i);
            if (row == null) continue;
            Map<String, Object> rowData = new HashMap<>();
            rowData.put(ROW_INDEX, i + 1); // 行号（从1开始）
            for (Map.Entry<String, String> entry : headerMapping.entrySet()) {
                int colIndex = Integer.parseInt(entry.getKey());
                String fieldName = entry.getValue();
                Cell cell = row.getCell(colIndex);
                Object value = getCellValue(cell);
                rowData.put(fieldName, value);
            }
            dataList.add(rowData);
        }
        return dataList;
    }

    public static Object getCellValue(Cell cell) {
        if(cell == null) return null;
        return switch (cell.getCellType()) {
            case STRING -> cell.getStringCellValue().trim();
            case NUMERIC -> DateUtil.isCellDateFormatted(cell) ? cell.getDateCellValue() : cell.getNumericCellValue();
            case BOOLEAN -> cell.getBooleanCellValue();
            case FORMULA -> cell.getCellFormula();
            default -> null;
        };
    }


    /**
     * convert class
     * @param clazz
     * @param dataList
     * @return
     */
    public static <T> List<T> convertToClass(Class<T> clazz , List<Map<String, Object>> dataList) {
        return dataList.stream().map(data -> {
            try {
                T entity = clazz.getDeclaredConstructor().newInstance();
                for (Map.Entry<String, Object> entry : data.entrySet()) {
                    if (ROW_INDEX.equals(entry.getKey())) continue;
                    String fieldName = entry.getKey();
                    Object value = entry.getValue();
                    if (value != null) {
                        Field field = clazz.getDeclaredField(fieldName);
                        field.setAccessible(true);
                        Object convertedValue = convertObjectToValue(value, field.getType());
                        field.set(entity, convertedValue);
                    }
                }
                return entity;
            } catch (Exception e) {
                throw new RuntimeException("转换实体对象失败: " + e.getMessage(), e);
            }
        }).collect(Collectors.toList());
    }


    /**
     * convert field
     * @param value
     * @param fieldType
     * @return
     */
    public static Object convertObjectToValue(Object value, Class<?> fieldType) {
        if (value == null || ObjectUtils.isEmpty(value)) return null;
        if (fieldType.isAssignableFrom(value.getClass())) return value;
        String strValue = value.toString().trim();
        if (fieldType == String.class) {
            return strValue;
        } else if (fieldType == Integer.class || fieldType == int.class) {
            return Double.valueOf(strValue).intValue();
        } else if (fieldType == Long.class || fieldType == long.class) {
            return Double.valueOf(strValue).longValue();
        } else if (fieldType == Double.class || fieldType == double.class) {
            return Double.valueOf(strValue);
        } else if (fieldType == Boolean.class || fieldType == boolean.class) {
            return Boolean.valueOf(strValue);
        } else if (fieldType == LocalDate.class) {
            return value instanceof Date ? ((Date) value).toInstant().atZone(java.time.ZoneId.systemDefault()).toLocalDate()
                    : LocalDate.parse(strValue, DateTimeFormatter.BASIC_ISO_DATE);
        } else if (fieldType == LocalDateTime.class) {
            return value instanceof Date ? ((Date) value).toInstant().atZone(java.time.ZoneId.systemDefault()).toLocalDateTime()
                    : LocalDateTime.parse(strValue,formatter);
        }
        return value;
    }


    /**
     * 获取类的 @ExcelColumn 字段参数
     * 对应 excel headers
     */
    public static List<ExcelColumnConfig> getExcelColumnConfigs(Class<?> clazz) {
        List<ExcelColumnConfig> excelColumnConfigs = new ArrayList<>();
        Field[] fields = clazz.getDeclaredFields();
        Arrays.stream(fields).forEach(field -> {
            ExcelColumn annotation = field.getAnnotation(ExcelColumn.class);
            if(annotation != null) {
                ExcelColumnConfig source = ExcelColumnConfig.builder(field, annotation);
                excelColumnConfigs.add(source);
            }
        });
        return excelColumnConfigs;
    }


    /**
     * 获取下载模板名称
     */
    public static String getExcelName(Class<?> clazz) {
        ExcelParser excelParser = clazz.getAnnotation(ExcelParser.class);
        if(excelParser != null) {
            return excelParser.templateName();
        }
        return "导出模板";
    }





}
